package com.ls.fw.open.interceptor;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.View;

import com.ls.fw.commons.open.annotation.OpenApi;
import com.ls.fw.mvc.springmvc.support.view.json.JsonView;
import com.ls.fw.open.support.Interceptor;
import com.ls.fw.open.support.OpenValidater;
import com.ls.fw.open.support.RequestContext;
import com.ls.fw.web.core.servlet.utils.HttpUtils;

/**
 * 开放接口拦截器
 * 
 * @author lisheng
 * @date 2015年12月16日 下午8:15:23
 * @version V1.0
 */
public class OpenInterceptor extends OpenValidater implements HandlerInterceptor {
	
	public static final String REQUEST_CONTEXT_NAME = "REQUEST_CONTEXT_NAME";

	protected Logger logger = LoggerFactory.getLogger(getClass());
	
	private List<Interceptor> processors = new ArrayList<Interceptor>();

    private boolean open = true;

	@Override
	public boolean preHandle(HttpServletRequest request,
			HttpServletResponse response, Object handler) throws Exception {
		Map<String,String> map = HttpUtils.getAllParaStr(request);
		boolean ret = true,isOpenApi = false; 
		 if (open && handler instanceof HandlerMethod) {
			 HandlerMethod handlerMethod = (HandlerMethod) handler;
			 if(this.isMatch(request, response,handlerMethod)) {
				 ret = false;
				 isOpenApi = true;
				 ret = this.validate(request, response,map, handlerMethod);
			 }
		 }else{
			this.logger.warn("handler is not HandlerMethod！");
		 }
		 if(ret && isOpenApi && open) {
			RequestContext requestContext = (RequestContext)request.getAttribute(REQUEST_CONTEXT_NAME);
			
			this.execBeforeProcessors(requestContext);
		 }
		return ret;
	}
	
	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		
		RequestContext requestContext = (RequestContext)request.getAttribute(REQUEST_CONTEXT_NAME);
		View view = modelAndView.getView();
		Object resultObject = null;
		if(view instanceof JsonView){
			JsonView dJsonView = (JsonView)view;
			resultObject = dJsonView.filterModel(modelAndView.getModel()) ; 
		}
		try{
			execAfterProcessors(requestContext,resultObject);
		}catch (Exception e) {}
	}
	
	@Override
	public void afterCompletion(HttpServletRequest request,
			HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
		RequestContext requestContext = (RequestContext)request.getAttribute(REQUEST_CONTEXT_NAME);
		if(requestContext != null){
			requestContext.setServerEndTime(System.currentTimeMillis());
			logger.info("^^^执行接口服务结束,耗时:" + requestContext.getApiExecTime() + "毫秒");
		}
	}
	
	@Override
	protected void initRequestContext(RequestContext requestContext,
			HttpServletRequest request, HttpServletResponse response,
			HandlerMethod handler) {
		
		HandlerMethod handlerMethod = (HandlerMethod) handler;
		OpenApi openApi = handlerMethod.getMethodAnnotation(OpenApi.class);
		openApi = openApi==null?handlerMethod.getBeanType().getAnnotation(OpenApi.class):openApi;
	    if(openApi!=null){
	    	requestContext.setNeedTimeout(openApi.needTimeout());
	    	requestContext.setNeedSign(openApi.needSign());
			requestContext.setMethodName(handlerMethod.getMethod().getName());
			requestContext.setExpirySeconds(openApi.expirySeconds());
			requestContext.setAllowRoles(openApi.allowRoles());
			requestContext.setDenyRoles(openApi.denyRoles());
			request.setAttribute(REQUEST_CONTEXT_NAME, requestContext);
		}
	}

	
	@Override
	public boolean isMatch(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handler) {
		HandlerMethod handlerMethod = (HandlerMethod) handler;
		OpenApi pApi =  handlerMethod.getMethodAnnotation(OpenApi.class) ;
		if(pApi==null){
			pApi = handlerMethod.getBeanType().getAnnotation(OpenApi.class);
		}
		return pApi!=null;
	}
	
	
	private void execBeforeProcessors(RequestContext requestContext){
		for (Interceptor apiProcessor : processors) {
			if(apiProcessor.isMatch(requestContext)){
				apiProcessor.beforeService(requestContext);
			}
		}
	}
	
	private void execAfterProcessors(RequestContext requestContext, Object resultObject){
		for (Interceptor apiProcessor : processors) {
			if(apiProcessor.isMatch(requestContext)){
				apiProcessor.afterService(requestContext,resultObject);
			}
		}
	}

	public void setProcessors(List<Interceptor> processors) {
		this.processors = processors;
	}

	public boolean isOpen() {
		return open;
	}

	public void setOpen(boolean open) {
		this.open = open;
	}

}
